home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 1.iso / dist / fw_exmh.idb / usr / freeware / lib / exmh-2.5 / getnews.tcl.z / getnews.tcl
Text File  |  2002-07-08  |  8KB  |  320 lines

  1. #
  2. # getnews.tcl  -  NNTP retrieve client for exmh
  3. # Needs tcl7.5/tk4.1 or above.
  4. # Chris Keane (Chris.Keane@comlab.ox.ac.uk)
  5. # 26-Feb-97
  6.  
  7.  
  8. proc GetNews {} {
  9.  
  10.     global NNTP
  11.  
  12.     if {![llength $NNTP(groups)]} {
  13.     Exmh_Status "No groups specified to retrieve"
  14.     return
  15.     }
  16.  
  17.     BgAction "News" GetNewsBg
  18. }
  19.  
  20. proc GetNewsBg {} {
  21.     busy Exmh_Status "Retrieve news: [GetNewsInt]"
  22. }
  23.  
  24. proc GetNewsInt {} {
  25.  
  26.     global NNTP mhProfile env
  27.  
  28.     if {![llength $NNTP(newsrc)]} {
  29.     set newsrc {~/.newsrc}
  30.     } else {
  31.     set newsrc $NNTP(newsrc)
  32.     }
  33.  
  34.     if {[file exists $newsrc]} {
  35.     if {[catch {open $newsrc} rcfile]} {
  36.         return "cannot open file $newsrc\n$rcfile"
  37.     }
  38.     } else {
  39.     set rcfile {}
  40.     }
  41.     Exmh_Status "Connecting to server $NNTP(host)..."
  42.     if {[catch {socket $NNTP(host) $NNTP(port)} nntpskt]} {
  43.     if {[string length $rcfile]} {
  44.         close $rcfile
  45.     }
  46.     return $nntpskt
  47.     }
  48.  
  49.     set line [NNTPReply $nntpskt]
  50.     if {[string first 200 $line] && [string first 201 $line]} {
  51.     NNTPClose $nntpskt $rcfile
  52.     return $line
  53.     }
  54.  
  55.     # Open the .newsrc file and extract the lines relating to the groups
  56.     # we're going to retrieve
  57.  
  58.     set gcount 0
  59.     set grps $NNTP(groups)
  60.     while {[string length $rcfile] && [llength $grps] && [gets $rcfile line] != -1} {
  61.     if {![regexp {^([0-9A-Za-z+&-\._]+)[:!][     ]*([0-9,-]+)} $line match group articles]} {
  62.         continue
  63.     }
  64.     set indx [lsearch -exact $grps $group]
  65.     if {$indx != -1} {
  66.         set thegrps($gcount) $group
  67.         set thearts($gcount) $articles
  68.         incr gcount
  69.         set grps [lreplace $grps $indx $indx]
  70.     }
  71.     }
  72.  
  73.     # If there are any groups which weren't in the .newsrc file, set their
  74.     # "articles which have been read" list to {}
  75.     foreach group $grps {
  76.     set thegrps($gcount) $group
  77.     set thearts($gcount) {}
  78.     incr gcount
  79.     }
  80.  
  81.     # make a temp directory for putting articles in while we work
  82.     if {![file isdirectory $mhProfile(path)/MyIncTmp]} {
  83.     exec mkdir $mhProfile(path)/MyIncTmp
  84.     }
  85.  
  86.     # Now get the articles from the server
  87.     set thisg 0
  88.     set acount 0
  89.     set ecount [file tail [Mh_Path MyIncTmp new]]
  90.     Exmh_Status "Retrieving articles..."
  91.     while {$thisg < $gcount} {
  92.     NNTPCommand $nntpskt "GROUP $thegrps($thisg)"
  93.     set line [NNTPReply $nntpskt]
  94.     if ![string first 480 $line] {
  95.         set ok [NNTPAuthenticate $nntpskt]
  96.         if $ok {
  97.         NNTPCommand $nntpskt "GROUP $thegrps($thisg)"
  98.         set line [NNTPReply $nntpskt]
  99.         }
  100.     }    
  101.     if {[string first 211 $line]} {
  102.         Exmh_Status "Cannot select newsgroup $thegrps($thisg)"
  103.         Exmh_Debug "Line: $line"
  104.         set thearts($thisg) "X"
  105.         incr thisg
  106.         continue
  107.     }
  108.  
  109.     if {![regexp {^211 ([0-9]+) ([0-9]+) ([0-9]+)} $line match num first last]} {
  110.         NNTPClose $nntpskt $rcfile
  111.         return "cannot parse server response"
  112.     }
  113.  
  114.     if {$num == 0} {
  115.         incr thisg
  116.         continue
  117.     }
  118.  
  119.     # start reading at the next unread article in this group
  120.     if {[regexp {^([0-9]+[,-])*([0-9]+)$} $thearts($thisg) match num tlast]
  121.         && $tlast >= $first} {
  122.         set first [expr $tlast + 1]
  123.     }
  124.  
  125.     set line 423
  126.     while {![string first 423 $line] || ![string first 430 $line]} {
  127.         if {$first > $last} {
  128.         break
  129.         }
  130.         NNTPCommand $nntpskt "STAT $first"
  131.         set line [NNTPReply $nntpskt]
  132.         if {![string first 223 $line]} {
  133.         break
  134.         }
  135.         if {[string first 423 $line] && [string first 430 $line]} {
  136.         NNTPClose $nntpskt $rcfile
  137.         return $line
  138.         }
  139.         incr first
  140.     }
  141.  
  142.     # if we get a 423 or 430 back, there were no further articles anyway
  143.     if {![string first 423 $line] || ![string first 430 $line]} {
  144.         incr thisg
  145.         continue
  146.     }
  147.  
  148.     # otherwise we must have got a 223, i.e. the article is selected
  149.     Exmh_Status "Reading group $thegrps($thisg) (max [expr $last-$first+1] articles)..."
  150.     while {![string first 223 $line]} {
  151.         NNTPCommand $nntpskt "ARTICLE"
  152.         set line [NNTPReply $nntpskt]
  153.         if {[string first 220 $line]} {
  154.         NNTPClose $nntpskt $rcfile
  155.         return "unexpected server response"
  156.         }
  157.         if {![regexp {^220 ([0-9]+)} $line match anum]} {
  158.         NNTPClose $nntpskt $rcfile
  159.         return "cannot parse server response"
  160.         }
  161.         if {[catch {open $mhProfile(path)/MyIncTmp/[expr $ecount+$acount] {WRONLY CREAT EXCL}} afile]} {
  162.         NNTPClose $nntpskt $rcfile
  163.         return "cannot write temp article file\n$afile"
  164.         }
  165.         set line [gets $nntpskt]
  166.         while {![regexp {^\.$} $line]} {
  167.         # two leading .'s should be compressed into one
  168.         regexp {^\.(\..*)} $line match line
  169.         puts $afile $line
  170.         set line [gets $nntpskt]
  171.         }
  172.         close $afile
  173.  
  174.         NNTPCommand $nntpskt "NEXT"
  175.         set line [NNTPReply $nntpskt]
  176.         if {[string first 223 $line] && [string first 421 $line]} {
  177.         NNTPClose $nntpskt $rcfile
  178.         return $line
  179.         }
  180.         incr acount
  181.     }
  182.     # update the article references for the new .newsrc file
  183.     set thearts($thisg) [AL_Update $thearts($thisg) $anum]
  184.     incr thisg
  185.     }
  186.  
  187.     if {$acount} {
  188.     Inc_Presort 0
  189.     Exmh_Status "Writing .newsrc file..."
  190.     if {[string length $rcfile]} {
  191.         seek $rcfile 0
  192.         set oldrc [glob $newsrc]
  193.         set newsrc $newsrc.exmh
  194.     }
  195.     if {[catch {open $newsrc w} nrcfile]} {
  196.         NNTPClose $nntpskt $rcfile
  197.         return "cannot write new .newsrc file\n$nrcfile"
  198.     }
  199.  
  200.     # re-parse the old .newsrc file, replacing the relevant article numbers
  201.     # with their new values
  202.  
  203.     set thisg 0
  204.     while {[string length $rcfile] && [gets $rcfile line] != -1} {
  205.         if {$thisg >= $gcount || ![regexp {^([0-9A-Za-z+&-\._]+)([:!][     ]*)([0-9]+[,-])*[0-9]+$} $line match group chaff first] || [string compare $group $thegrps($thisg)]} {
  206.         puts $nrcfile $line
  207.         continue
  208.         }
  209.         if {[string match X $thearts($thisg)]} {
  210.         # we didn't manage to select this group
  211.         puts $nrcfile $line
  212.         } else {
  213.         puts $nrcfile "$group$chaff$thearts($thisg)"
  214.         }
  215.         incr thisg
  216.     }
  217.     while {$thisg < $gcount} {
  218.         if {![string match X $thearts($thisg)]} {
  219.         puts $nrcfile "$thegrps($thisg): $thearts($thisg)"
  220.         }
  221.         incr thisg
  222.     }
  223.     } else {
  224.     set nrcfile {}
  225.     }
  226.  
  227.     NNTPClose $nntpskt [list $rcfile $nrcfile]
  228.     if {[string length $rcfile] && [string length $nrcfile] && [catch {
  229.         exec mv -f $oldrc $oldrc.old
  230.         exec mv -f [glob $newsrc] $oldrc
  231.         } err]} {
  232.     return "failed to rename .newsrc files\n$err"
  233.     }
  234.     return "$acount new articles retrieved"
  235. }
  236.  
  237. # parse the existing .newsrc entry and update it with new values
  238. proc AL_Update {rcentry next} {
  239.  
  240.     # a few different cases here; first, if the existing entry is empty
  241.     if {![string length $rcentry]} {
  242.     set rcentry 1
  243.     }
  244.  
  245.     # if the last part of the existing entry is a single number
  246.     if {[regexp {^([0-9]+(-[0-9]+)?,)*([0-9]+)$} $rcentry match fst snd last]} {
  247.     if {$next == $last} {
  248.         return $rcentry
  249.     } else {
  250.         return "$rcentry-$next"
  251.     }
  252.  
  253.     # otherwise the last part of the existing entry must be a range mmm-nnn
  254.     } else {
  255.     regexp {^(([0-9]+(-[0-9]+)?,)*[0-9]+-)([0-9]+)$} $rcentry match fst snd thd last
  256.     if {$next == $last} {
  257.         # this case shouldn't actually ever happen, but just in case... 8-)
  258.         return $rcentry
  259.     } else {
  260.         return "$fst$next"
  261.     }
  262.     }
  263. }
  264.  
  265. proc NNTPCommand {nntpskt cmd} {
  266.     puts $nntpskt $cmd
  267.     regsub {pass.*$} $cmd {pass *****} cmd
  268.     Exmh_Debug NNTPCommand: $cmd
  269.     flush $nntpskt
  270. }
  271.  
  272. proc NNTPReply {nntpskt} {
  273.     set line [gets $nntpskt]
  274.     Exmh_Debug NNTPReply: $line
  275.     return $line
  276. }
  277.  
  278. proc NNTPClose {nntpskt rcfiles} {
  279.     global mhProfile
  280.  
  281.     puts $nntpskt QUIT
  282.     close $nntpskt
  283.     foreach rcf $rcfiles {
  284.     if {[string length $rcf]} {
  285.         close $rcf
  286.     }
  287.     }
  288.     File_Delete $mhProfile(path)/MyIncTmp/$mhProfile(mh-sequences)
  289.     catch {exec rmdir $mhProfile(path)/MyIncTmp}
  290. }
  291.  
  292. #
  293. # 'Original' AUTHINFO implementation
  294. # i.e., not AUTHINFO SIMPLE or AUTHINFO GENERIC
  295. # see 'Common NNTP extensions'
  296. #
  297. proc NNTPAuthenticate {sock} {
  298.  
  299.     global NNTP
  300.  
  301.     if {$NNTP(user)==""} {
  302.     tk_messageBox -message {News server requires authentication.
  303.         Check username and password in NNTP preferences} -type ok
  304.     return 0
  305.     }
  306.  
  307.     NNTPCommand $sock "authinfo user $NNTP(user)"
  308.     set line [NNTPReply $sock]
  309.     NNTPCommand $sock "authinfo pass $NNTP(pass)"
  310.     set line [NNTPReply $sock]
  311.     if [string first 281 $line] {
  312.     tk_messageBox -message {Authentication to NNTP server failed.
  313.         Check username and password in NNTP preferences} -type ok
  314.     return 0
  315.     } else {
  316.     return 1
  317.     }
  318. }
  319.